package org.dtrd.modules.archive.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dtrd.common.util.CheckUtil;
import org.dtrd.common.util.RedisUtil;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.archive.entity.bean.report.PhysicalReport;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchivePhysical;
import org.dtrd.modules.archive.mapper.DtrdEntRdPhysicalMapper;
import org.dtrd.modules.archive.service.IDtrdEntRdPhysicalService;
import org.dtrd.modules.system.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Optional;
import java.util.StringJoiner;

/**
 * @author 萧
 * @date 2021-10-01 22:47:27
 **/
@Service
@DS("multi-datasource1")
public class DtrdEntRdPhysicalServiceImpl extends ServiceImpl<DtrdEntRdPhysicalMapper, DtrdEntRdArchivePhysical> implements IDtrdEntRdPhysicalService {

    @Autowired
    private ISysDictService sysDictService;

    private final static String exam = "pubExam";

    private final static Integer ABNORMAL = 2;

    @Resource
    @Lazy
    private RedisUtil redisUtil;

    @Override
    public PhysicalReport getPatientPhysicalReport(Integer patientId) {
        DtrdEntRdArchivePhysical po = getPatientPhysical(patientId);
        PhysicalReport report = null;
        if (po != null) {
            report = new PhysicalReport().parseFromPO(po);
            // region 皮肤检查
            PhysicalReport.SkinCheck skinCheck = null;
            if (CheckUtil.isNotNull(po.getSkinExam(), po.getSkinSymptom(),
                    po.getInsulinInjection(), po.getInsulinInjectionSymptom())) {
                skinCheck = new PhysicalReport.SkinCheck();
                Integer skinExam = po.getSkinExam();
                if (skinExam != null && skinExam.equals(ABNORMAL)) {
                    skinCheck.setSkinExam(Constant.Exam.ABNORMAL.getName());
                    String symptoms = po.getSkinSymptom();
                    if (StrUtil.isNotBlank(symptoms)) {
                        String skinSymptom = translate(po.getSkinSymptom(), po.getSkinSymptomOther(), "pubDossierSkinSymptom");
                        skinCheck.setSkinSymptom(skinSymptom);
                    }
                } else {
                    skinCheck.setSkinExam(Constant.Exam.NORMAL.getName());
                }
                // 胰岛素注射部位
                Integer injection = po.getInsulinInjection();
                if (injection != null && injection.equals(ABNORMAL)) {
                    skinCheck.setInsulinInjection(Constant.Exam.ABNORMAL.getName());
                    String symptoms = po.getInsulinInjectionSymptom();
                    if (StrUtil.isNotBlank(symptoms)) {
                        String injectionSymptom = translate(symptoms, po.getInsulinInjectionSymptomOther(), "pubDossierInsulinSymptom");
                        skinCheck.setInsulinInjectionSymptom(injectionSymptom);
                    }
                } else {
                    skinCheck.setInsulinInjection(Constant.Exam.NORMAL.getName());
                }
            }
            report.setSkinCheck(skinCheck);
            // endregion
            // region 眼底检查
            PhysicalReport.EyeCheck eyeCheck = null;
            if (CheckUtil.isNotNull(po.getEyeCottonWoolSpots(), po.getEyeVenousBeadedChanges(),
                    po.getEyeThickeningPosteriorRetina(), po.getEyeFundusBleeding(),
                    po.getEyeIntraretinalHemorrhage(), po.getEyeNeovascularization(),
                    po.getEyePreretinalHemorrhage(), po.getEyeMicrovascularAbnormalitiesInRetina(),
                    po.getEyeVitreousHemorrhage(), po.getEyeMicroaneurysm(), po.getEyePreretinalHemorrhage(),
                    po.getEyeHardExudation())) {
                eyeCheck = new PhysicalReport.EyeCheck();
                if (po.getEyeMicroaneurysm() != null) {
                    eyeCheck.setEyeMicroaneurysm(Constant.YesOrNo.valueOf(po.getEyeMicroaneurysm()).getName());
                }
                if (po.getEyeCottonWoolSpots() != null) {
                    eyeCheck.setEyeCottonWoolSpots(Constant.YesOrNo.valueOf(po.getEyeCottonWoolSpots()).getName());
                }
                if (po.getEyeFundusBleeding() != null) {
                    eyeCheck.setEyeFundusBleeding(Constant.YesOrNo.valueOf(po.getEyeFundusBleeding()).getName());
                }
                if (po.getEyeThickeningPosteriorRetina() != null) {
                    eyeCheck.setEyeThickeningPosteriorRetina(Constant.YesOrNo.valueOf(po.getEyeThickeningPosteriorRetina()).getName());
                }
                if (po.getEyeNeovascularization() != null) {
                    eyeCheck.setEyeNeovascularization(Constant.YesOrNo.valueOf(po.getEyeNeovascularization()).getName());
                }
                if (po.getEyeVitreousHemorrhage() != null) {
                    eyeCheck.setEyeVitreousHemorrhage(Constant.YesOrNo.valueOf(po.getEyeVitreousHemorrhage()).getName());
                }
                if (po.getEyePreretinalHemorrhage() != null) {
                    eyeCheck.setEyePreretinalHemorrhage(Constant.YesOrNo.valueOf(po.getEyePreretinalHemorrhage()).getName());
                }
                if (po.getEyeIntraretinalHemorrhage() != null) {
                    switch (po.getEyeIntraretinalHemorrhage()){
                        case 1: eyeCheck.setEyeIntraretinalHemorrhage("有(任一象限中<20处)");break;
                        case 2: eyeCheck.setEyeIntraretinalHemorrhage("有(任一象限中>=20处)");break;
                        case 3: eyeCheck.setEyeIntraretinalHemorrhage("无");break;
                    }
                }
                if (po.getEyeHardExudation() != null) {
                    switch (po.getEyeHardExudation()){
                        case 1: eyeCheck.setEyeHardExudation("有(非后极区)");break;
                        case 2: eyeCheck.setEyeHardExudation("有(后极区)");break;
                        case 3: eyeCheck.setEyeHardExudation("无");break;
                    }
                }
                if (po.getEyeVenousBeadedChanges() != null) {
                    switch (po.getEyeVenousBeadedChanges()){
                        case 1: eyeCheck.setEyeVenousBeadedChanges("有(<=2个象限)");break;
                        case 2: eyeCheck.setEyeVenousBeadedChanges("有(>2个象限）");break;
                        case 3: eyeCheck.setEyeVenousBeadedChanges("无");break;
                    }
                }
                if (po.getEyeMicrovascularAbnormalitiesInRetina() != null) {
                    eyeCheck.setEyeMicrovascularAbnormalitiesInRetina(Constant.EyeCheck.valueOf(po.getEyeMicrovascularAbnormalitiesInRetina()).getName());
                }
            }
            report.setEyeCheck(eyeCheck);
            // endregion
            // region糖足检查
            PhysicalReport.FootCheck footCheck = null;
            Integer footInspection = po.getFootSugarFootInspection();
            if (CheckUtil.isNotNull(po.getFootAcupuncturePain(), po.getFootTemperatureSense(),
                    po.getFootVibrationSense(), po.getFootNerveConduction(), po.getFootSugarFootInspection(),
                    po.getFootPalpationOfDorsalisPedisArtery(), po.getFootPressureSense(), po.getFootAnkleReflex())
                    && footInspection != null && footInspection.equals(Constant.Exam.ABNORMAL.getType())) {
                footCheck = new PhysicalReport.FootCheck();
                footCheck.setFootSugarFootInspection(Constant.Exam.ABNORMAL.getName());
                Integer artery = po.getFootPalpationOfDorsalisPedisArtery();
                if (artery != null) {
                    footCheck.setFootPalpationOfDorsalisPedisArtery(Constant.PeripheralItem.valueOf(artery).getName());
                }
                Integer reflex = po.getFootAnkleReflex();
                if (reflex != null) {
                    footCheck.setFootAnkleReflex(Constant.PeripheralItem.valueOf(reflex).getName());
                }
                Integer nerveConduction = po.getFootNerveConduction();
                if (nerveConduction != null) {
                    footCheck.setFootNerveConduction(Constant.PeripheralItem.valueOf(nerveConduction).getName());
                }
                Integer vibrationSense = po.getFootVibrationSense();
                if (vibrationSense != null) {
                    footCheck.setFootVibrationSense(Constant.PeripheralItem.valueOf(vibrationSense).getName());
                }
                Integer pain = po.getFootAcupuncturePain();
                if (pain != null) {
                    footCheck.setFootAcupuncturePain(Constant.PeripheralItem.valueOf(pain).getName());
                }
                Integer temperatureSense = po.getFootTemperatureSense();
                if (temperatureSense != null) {
                    footCheck.setFootTemperatureSense(Constant.PeripheralItem.valueOf(temperatureSense).getName());
                }
                Integer footPressureSense = po.getFootPressureSense();
                if (footPressureSense != null) {
                    footCheck.setFootPressureSense(Constant.PeripheralItem.valueOf(footInspection).getName());
                }
            }
            report.setFootCheck(footCheck);
            // endregion
            // region 其他检查
            PhysicalReport.OtherCheck otherCheck = null;
            if (CheckUtil.isNotNull(po.getTcpo2(), po.getLegsSkinTemp(), po.getClaudicationTest(),
                    po.getCarotidAuscultation(), po.getTbi(), po.getAbiExerciseTest(),
                    po.getFemoralAuscultation(), po.getAbi())) {
                otherCheck = new PhysicalReport.OtherCheck();
                Integer claudicationTest = po.getClaudicationTest();
                if (claudicationTest != null) {
                    switch (claudicationTest) {
                        case 1:
                            otherCheck.setClaudicationTest("阳性");
                            break;
                        case 2:
                            otherCheck.setClaudicationTest("阴性");
                            break;
                    }
                }
                Integer auscultation = po.getCarotidAuscultation();
                if (auscultation != null) {
                    otherCheck.setCarotidAuscultation(Constant.AuscultationStatus.valueOf(auscultation).getName());
                }
                Integer femoralAuscultation = po.getFemoralAuscultation();
                if (femoralAuscultation != null) {
                    otherCheck.setFemoralAuscultation(Constant.AuscultationStatus.valueOf(femoralAuscultation).getName());
                }
                Integer legsSkinTemp = po.getLegsSkinTemp();
                if (legsSkinTemp != null) {
                    otherCheck.setLegsSkinTemp(Constant.NormalStatus.valueOf(legsSkinTemp).getName());
                }
                Integer nerveConduction = po.getNerveConduction();
                if (nerveConduction != null){
                    switch (nerveConduction){
                        case 1: otherCheck.setNerveConduction("正常");break;
                        case 2: otherCheck.setNerveConduction("异常");break;
                    }
                }
                Float abi = po.getAbi();
                if (abi != null) {
                    otherCheck.setAbi(abi + "");
                }
                Integer abiExerciseTest = po.getAbiExerciseTest();
                if (abiExerciseTest != null) {
                    otherCheck.setAbiExerciseTest(Constant.ABI.valueOf(abiExerciseTest).getName());
                }
                Integer tbi = po.getTbi();
                if (tbi != null) {
                    otherCheck.setTbi(Constant.TBI.valueOf(tbi).getName());
                }
                Integer tcpo2 = po.getTcpo2();
                if (tcpo2 != null) {
                    otherCheck.setTcPO2(Constant.TcPO2.valueOf(tcpo2).getName());
                }
            }
            report.setOther(otherCheck);
            // endregion
        }
        return report;
    }

    @Override
    public DtrdEntRdArchivePhysical getPatientPhysical(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdArchivePhysical> wrapper = Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId)
                .eq(DtrdEntRdArchivePhysical::getIsDel, 0).last(" limit 1 ");
        DtrdEntRdArchivePhysical po = getOne(wrapper);
        return po;
    }

    private String translate(String symptom, String other, String dicCode) {
        StringJoiner joiner = new StringJoiner("、");
        String[] strings = symptom.split(",");
        for (String s : strings) {
            String text = sysDictService.queryDictTextByKey(dicCode, s);
            if (StrUtil.isNotBlank(text)) {
                if (text.equals(Constant.other)) {
                    Optional.ofNullable(other).ifPresent(joiner::add);
                } else {
                    joiner.add(text);
                }
            }
        }
        return joiner.toString();
    }

    @Override
    public boolean saveOrUpdateByPatientId(DtrdEntRdArchivePhysical po, Integer patientId) {
        LambdaUpdateWrapper<DtrdEntRdArchivePhysical> wrapper = Wrappers.lambdaUpdate(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId);
        return saveOrUpdate(po, wrapper);
    }

    @Override
    public void saveOrUpdatePatientInfo(Integer patientId, Float height, Float weight) {
        DtrdEntRdArchivePhysical physical = new DtrdEntRdArchivePhysical();
        physical.setPatientId(patientId);
        physical.setHeight(height);
        physical.setWeight(weight);
        LambdaUpdateWrapper<DtrdEntRdArchivePhysical> updateWrapper = Wrappers.lambdaUpdate(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId);
        saveOrUpdate(physical, updateWrapper);
    }

    @Override
    public DtrdEntRdArchivePhysical getByPatientId(Integer patientId) {
        LambdaUpdateWrapper<DtrdEntRdArchivePhysical> wrapper = Wrappers.lambdaUpdate(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId)
                .orderByDesc(DtrdEntRdArchivePhysical::getCreateTime)
                .last("limit 1");
        return getOne(wrapper);
    }

    @Override
    public Float getPatientHeight(Integer patientId) {
        Double height = (Double) redisUtil.get(patientId + "Height");
        if (height != null) {
            return height.floatValue();
        } else {
            DtrdEntRdArchivePhysical physical = getByPatientId(patientId);
            Float physicalHeight = physical.getHeight();
            redisUtil.set(patientId + "Height", physicalHeight);
            return physicalHeight;
        }
    }

    @Override
    public void updatePatientHeightOrWeight(Integer patientId, Integer patientsHeight, Float patientsWeight) {
        DtrdEntRdArchivePhysical physical = getByPatientId(patientId);
        if (physical == null) {
            physical = new DtrdEntRdArchivePhysical();
        }
        physical.setPatientId(patientId);
        physical.setHeight(Optional.ofNullable(patientsHeight).map(Integer::floatValue).orElse(null));
        physical.setWeight(patientsWeight);
        updateByPatientId(physical, patientId);
    }

    private boolean updateByPatientId(DtrdEntRdArchivePhysical po, Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdArchivePhysical> wrapper = Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId);
        return update(po, wrapper);
    }

}
